package ckw.gui;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import ckw.database.model.Node;
import core.database.NodeType;
import core.utils.LocatorUriChecker;

public class WzdPgAddEditNode extends ModelValidationWizardPage {

	private boolean addNode;
	private Node node;
	private NodeType[] nodeTypes;

	String editIP = "";
	String editPort = "";

	private Text txtName;
	private Text txtAddress;
	private Text txtIp;
	private Text txtPort;
	private ComboViewer cmbVwrType;

	/**
	 * Create the wizard.
	 */
	public WzdPgAddEditNode(boolean addNode, Node node, NodeType[] nodeTypes) {
		super("WzdPgAddEditNode");

		if (addNode) {
			setTitle("Add Node");
			setDescription("Add new Node to the Communication Tree.");
		} else {
			setTitle("Edit Node");
			setDescription("Edit an existing Node of the Communication Tree.");
		}

		this.addNode = addNode;
		this.node = node;
		this.nodeTypes = nodeTypes;
	}

	/**
	 * Create contents of the wizard.
	 * 
	 * @param parent
	 */
	public void createControl(Composite parent) {
		Composite container = new Composite(parent, SWT.NULL);

		setControl(container);
		container.setLayout(new GridLayout(4, false));

		new Label(container, SWT.NONE).setText("Name:");

		txtName = new Text(container, SWT.BORDER);
		txtName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));

		new Label(container, SWT.NONE).setText("Address:");

		txtAddress = new Text(container, SWT.BORDER);
		txtAddress.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));

		new Label(container, SWT.NONE).setText("IP:");

		txtIp = new Text(container, SWT.BORDER);
		txtIp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

		new Label(container, SWT.NONE).setText("Port:");

		txtPort = new Text(container, SWT.BORDER);
		txtPort.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

		new Label(container, SWT.NONE).setText("Type:");

		cmbVwrType = new ComboViewer(container, SWT.READ_ONLY);
		Combo cmbType = cmbVwrType.getCombo();
		cmbType.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
		cmbVwrType.setContentProvider(new ArrayContentProvider());

		initValues();
		setVerifyListeners();
	}

	private void initValues() {
		if (addNode) {
			cmbVwrType.setInput(nodeTypes);
			if (nodeTypes.length == 1) {
				cmbVwrType.setSelection(new StructuredSelection(node.getNodeType()));
				cmbVwrType.getCombo().setEnabled(false);
			}

			setPageComplete(false);
		} else {
			txtName.setText(node.getName());
			txtAddress.setText(node.getAddress());
			txtIp.setText(node.getIp());
			txtPort.setText(node.getPort());

			editIP = node.getIp();
			editPort = node.getPort();

			cmbVwrType.add(node.getNodeType());
			cmbVwrType.setSelection(new StructuredSelection(node.getNodeType()));
			cmbVwrType.getCombo().setEnabled(false);
		}
	}

	private void setVerifyListeners() {
		txtName.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent arg0) {
				validate();
			}
		});

		txtAddress.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent arg0) {
				validate();
			}
		});

		txtIp.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent arg0) {
				validate();
			}
		});

		txtPort.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent arg0) {
				validate();
			}
		});

		cmbVwrType.addSelectionChangedListener(new ISelectionChangedListener() {
			@Override
			public void selectionChanged(SelectionChangedEvent arg0) {
				validate();
			}
		});
	}

	@Override
	protected void validate() {

		boolean isLocatorURINotValid = false;

		String name = txtName.getText().trim();
		String address = txtAddress.getText().trim();
		String ip = txtIp.getText().trim();
		String port = txtPort.getText().trim();

		String lastIP = "";
		String lastPort = "";
		// TODO http://commons.apache.org/proper/commons-validator/apidocs/org/apache/commons/validator/routines/InetAddressValidator.html <-- to może być dobre do walidacji (IPv6)

		String numberPattern = "^-?(\\d)*$";

		if (MainWindow.isInDebugMode()) {
			clearErrorState();
			return;
		}

		// error
		if (name.length() == 0) {
			setErrorState("Name cannot be empty.");
			return;
		}
		if (address.length() == 0) {
			setErrorState("Address cannot be empty.");
			return;
		}
		if (ip.length() == 0) {
			setErrorState("IP cannot be empty.");
			return;
		}
		if (!LocatorUriChecker.isProperIpString(ip)) {
			setErrorState("IP must be of proper format (e.g. 192.168.1.1).");
			return;
		}
		if (lastIP.compareTo(ip) != 0) {
			lastIP = ip;
			isLocatorURINotValid = manager.isNodeLocatorUriTaken(ip, port);
		}
		if (port.length() == 0) {
			setErrorState("Port cannot be empty.");
			return;
		}
		if (!port.matches(numberPattern)) {
			setErrorState("Port must be a number.");
			return;
		}
		if (lastPort.compareTo(port) != 0) {
			lastPort = port;
			isLocatorURINotValid = manager.isNodeLocatorUriTaken(ip, port);
		}
		if (addNode == false && ip.compareTo(editIP) == 0 && port.compareTo(editPort) == 0) {
			isLocatorURINotValid = false;
		}
		if (isLocatorURINotValid) {
			setErrorState("Node with selected port:ip combination already exists.");
			return;
		}
		if (0 > Integer.valueOf(port) || Integer.valueOf(port) > 65535) {
			setErrorState("Port must be a number between 0 and 65535.");
			return;
		}
		if (((StructuredSelection) cmbVwrType.getSelection()).isEmpty()) {
			setErrorState("Type must be selected.");
			return;
		}

		// warning
		if (0 <= Integer.valueOf(txtPort.getText()) && Integer.valueOf(txtPort.getText()) <= 1023) {
			setWarningState("It is discouraged to use a Port number between 0 and 1023.");
			return;
		}

		// ok
		clearErrorState();
	}

	@Override
	public void update() {
		node.setName(txtName.getText().trim());
		node.setAddress(txtAddress.getText().trim());
		node.setIp(txtIp.getText().trim());
		node.setPort(txtPort.getText().trim());
		IStructuredSelection structuredSelection = (IStructuredSelection) cmbVwrType.getSelection();
		node.setNodeType((NodeType) structuredSelection.getFirstElement());
	}

}
